// 版权所有2011 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package template

import (
	"reflect"
	"sync"
	"text/template/parse"
)

// common保存相关模板共享的信息。
type common struct {
	tmpl   map[string]*Template // 从名称映射到定义的模板。
	muTmpl sync.RWMutex         // 保护tmpl 
	option option
	// 我们使用两个映射，一个用于解析，一个用于执行。
	// 这种分离使API更干净，因为它不会向客户端公开反射。
	muFuncs    sync.RWMutex // 保护parseFuncs和execFuncs 
	parseFuncs FuncMap
	execFuncs  map[string]reflect.Value
}

// 模板是已解析模板的表示形式。解析。Tree 
// 字段仅导出供html/template使用，应将
// 视为所有其他客户端都未导出。
type Template struct {
	name string
	*parse.Tree
	*common
	leftDelim  string
	rightDelim string
}

// New使用给定的名称分配一个新的、未定义的模板。
func New(name string) *Template {
	t := &Template{
		name: name,
	}
	t.init()
	return t
}

// Name返回模板的名称。
func (t *Template) Name() string {
	return t.name
}

// New分配一个新的未定义模板，该模板与给定模板关联，并使用相同的
// 分隔符。该关联是可传递的，允许一个模板使用{template}操作调用另一个模板。
// 
// 由于相关模板共享基础数据，模板构建
// 无法安全地并行完成。一旦构建好模板，它们
// 就可以并行执行。
func (t *Template) New(name string) *Template {
	t.init()
	nt := &Template{
		name:       name,
		common:     t.common,
		leftDelim:  t.leftDelim,
		rightDelim: t.rightDelim,
	}
	return nt
}

// init保证t有一个有效的公共结构。
func (t *Template) init() {
	if t.common == nil {
		c := new(common)
		c.tmpl = make(map[string]*Template)
		c.parseFuncs = make(FuncMap)
		c.execFuncs = make(map[string]reflect.Value)
		t.common = c
	}
}

// 克隆返回模板的副本，包括所有关联的
// 模板。未复制实际的表示形式，但
// 关联模板的名称空间为，因此在副本中进一步调用Parse将向副本中添加
// 模板，但不会向原始模板中添加。克隆可用于准备
// 通用模板，并在克隆完成后添加变体，将其与其他模板的变体定义
// 一起使用。
func (t *Template) Clone() (*Template, error) {
	nt := t.copy(nil)
	nt.init()
	if t.common == nil {
		return nt, nil
	}
	t.muTmpl.RLock()
	defer t.muTmpl.RUnlock()
	for k, v := range t.tmpl {
		if k == t.name {
			nt.tmpl[t.name] = nt
			continue
		}
		// 关联的模板共享nt的公共结构。
		tmpl := v.copy(nt.common)
		nt.tmpl[k] = tmpl
	}
	t.muFuncs.RLock()
	defer t.muFuncs.RUnlock()
	for k, v := range t.parseFuncs {
		nt.parseFuncs[k] = v
	}
	for k, v := range t.execFuncs {
		nt.execFuncs[k] = v
	}
	return nt, nil
}

// copy返回t的浅拷贝，参数设置为common。
func (t *Template) copy(c *common) *Template {
	return &Template{
		name:       t.name,
		Tree:       t.Tree,
		common:     c,
		leftDelim:  t.leftDelim,
		rightDelim: t.rightDelim,
	}
}

// AddParseTree将参数parse tree与模板t关联，为
// it指定名称。如果尚未定义模板，则此树将成为
// 其定义。如果已定义且已具有该名称，则替换现有的
// 定义；否则将创建、定义并返回一个新模板。
func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
	t.init()
	t.muTmpl.Lock()
	defer t.muTmpl.Unlock()
	nt := t
	if name != t.name {
		nt = t.New(name)
	}
	// 即使nt==t，我们也需要将其安装在公共位置。tmpl地图。
	if t.associate(nt, tree) || nt.Tree == nil {
		nt.Tree = tree
	}
	return nt, nil
}

// Templates返回与t关联的已定义模板的一个片段。
func (t *Template) Templates() []*Template {
	if t.common == nil {
		return nil
	}
	// 返回一个片段，这样我们就不会公开地图。
	t.muTmpl.RLock()
	defer t.muTmpl.RUnlock()
	m := make([]*Template, 0, len(t.tmpl))
	for _, v := range t.tmpl {
		m = append(m, v)
	}
	return m
}

// Delims将操作分隔符设置为指定的字符串，用于
// 后续的Parse、ParseFiles或ParseGlob调用。嵌套模板
// 定义将继承设置。空分隔符代表
// 对应的默认值：{{or}。
// 返回值是模板，因此可以链接调用。
func (t *Template) Delims(left, right string) *Template {
	t.init()
	t.leftDelim = left
	t.rightDelim = right
	return t
}

// Funcs将参数映射的元素添加到模板的函数映射中。
// 必须在解析模板之前调用它。
// 如果映射中的某个值不是具有适当返回值的函数，或者如果该名称在语法上不能用作模板中的函数，则会出现恐慌。
// 覆盖地图元素是合法的。返回值是模板
// 因此可以链接调用。
func (t *Template) Funcs(funcMap FuncMap) *Template {
	t.init()
	t.muFuncs.Lock()
	defer t.muFuncs.Unlock()
	addValueFuncs(t.execFuncs, funcMap)
	addFuncs(t.parseFuncs, funcMap)
	return t
}

// Lookup返回与t关联的具有给定名称的模板。
// 如果没有此类模板或模板没有定义，则返回nil。
func (t *Template) Lookup(name string) *Template {
	if t.common == nil {
		return nil
	}
	t.muTmpl.RLock()
	defer t.muTmpl.RUnlock()
	return t.tmpl[name]
}

// Parse将文本解析为t的模板体。
// 命名模板定义（{define…}）或者{block…}语句）在文本
// 中定义与t相关的其他模板，并从
// t本身的定义中删除。
// 
// 模板可以在后续的解析调用中重新定义。
// 如果模板定义的正文仅包含空格和注释，则该模板定义将被视为空，不会替换现有模板的正文。
// 这允许使用Parse添加新的命名模板定义，而无需覆盖模板主体。
func (t *Template) Parse(text string) (*Template, error) {
	t.init()
	t.muFuncs.RLock()
	trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins())
	t.muFuncs.RUnlock()
	if err != nil {
		return nil, err
	}
	// 将新解析的树（包括t的树）添加到我们的公共结构中。
	for name, tree := range trees {
		if _, err := t.AddParseTree(name, tree); err != nil {
			return nil, err
		}
	}
	return t, nil
}

// associate将新模板安装到与t关联的模板组中。已知这两个模板具有相同的结构。
// 布尔返回值报告是否将此树存储为t.tree。
func (t *Template) associate(new *Template, tree *parse.Tree) bool {
	if new.common != t.common {
		panic("internal error: associate not common")
	}
	if old := t.tmpl[new.name]; old != nil && parse.IsEmptyTree(tree.Root) && old.Tree != nil {
		// 如果存在同名模板，
		// 不要将其替换为空模板。
		return false
	}
	t.tmpl[new.name] = new
	return true
}
